#ifndef _RINGQUEUE_HPP_
#define _RINGQUEUE_HPP_

#include <iostream>
#include <vector>
#include <pthread.h>
#include "sem.hpp"

using namespace std;

const int g_default_num = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(int default_num = g_default_num)
        : _ring_queue(default_num),
          _num(g_default_num),
          c_step(0),
          p_step(0),
          _space(default_num),
          _data(0)
    {
        pthread_mutex_init(&_clock, nullptr);
        pthread_mutex_init(&_plock, nullptr);
    }
    ~RingQueue()
    {
        pthread_mutex_destroy(&_clock);
        pthread_mutex_destroy(&_plock);
    }

    void push(const T &in) // 生产者
    {
        _space.p(); // 先申请信号量，提高效率

        pthread_mutex_lock(&_plock);

        _ring_queue[p_step++] = in;
        p_step %= _num;

        pthread_mutex_unlock(&_plock);

        _data.v();
    }
    void pop(T *out)
    {
        pthread_mutex_lock(&_clock); // 同上

        _data.p();

        *out = _ring_queue[c_step++];
        c_step %= _num;

        pthread_mutex_unlock(&_clock);

        _space.v();
    }
    void debug()
    {
        cerr << "size：" << _ring_queue.size()
             << "，num: " << _num << endl;
    }

private:
    vector<T> _ring_queue;
    int _num;
    int c_step; // 消费下标
    int p_step; // 生产下标

    Sem _space;
    Sem _data;

    pthread_mutex_t _clock; // 消费者锁
    pthread_mutex_t _plock; // 生产者锁
};

#endif